package com.analysis.common;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import org.apache.commons.collections.CollectionUtils;

import com.analysis.model.KLine;
import com.analysis.model.Statistic;

public class CalculationUtil {
	
	public static double calculateExpense(double money,String type) {
		if(money<=0) {
			throw new IllegalArgumentException("Illegal number");
		}
		double expense = 0;
		if(money*0.00025<=5) {
			expense = 5+money*0.0002;
		}else {
			expense = money*(0.00025+0.0002);
		}
		if("sale".equalsIgnoreCase(type)) {		
			expense+=money*0.001;
		}
		return expense;
	}
	
	public static Statistic calStatistic(List<Double> data){
		if(CollectionUtils.isEmpty(data)){
			return new Statistic();
		}
		Double min,count = .0,max = min = data.get(0);
		for(int i=1;i<data.size();i++){
			Double each = data.get(i);
			count+=each;
			if(each<min){
				min = each;
			}
			if(each>max){
				max = each;
			}
		}
		Statistic statistic = new Statistic();
		statistic.setMax(max);
		statistic.setMin(min);
		statistic.setAvg(count/data.size());
		return statistic;
	}
	

	/**获取固定区间中K线收盘价最大值
	 * @param  list K线
	 * @param  interval 区间大小
	 * @return K线列表
	 */
	public static List<KLine> getCPriceMax(List<KLine> list, int interval) {
		List<KLine> tempList = new ArrayList<KLine>();
		List<KLine> maxRs = new ArrayList<KLine>();
		int count = 0;
		for (KLine kLine : list) {
			count++;
			tempList.add(kLine);
			if (count % interval == 0) {
				maxRs.add(getCMax(tempList));
				tempList.clear();
			}
			if (count == list.size()) {
				if (!(list.size() % interval == 0)) {
					maxRs.add(getCMax(tempList));
					tempList.clear();
				}
			}
		}
		return maxRs;
	}

	/**获取固定区间中K线当日最高价的最大值
	 * @param  list K线
	 * @param  interval 区间大小
	 * @return K线列表
	 */
	public static List<KLine> getHPriceMax(List<KLine> list, int interval) {
		List<KLine> tempList = new ArrayList<KLine>();
		List<KLine> maxRs = new ArrayList<KLine>();
		int count = 0;
		for (KLine kLine : list) {
			count++;
			tempList.add(kLine);
			if (count % interval == 0) {
				maxRs.add(getHMax(tempList));
				tempList.clear();
			}
			if (count == list.size()) {
				if (!(list.size() % interval == 0)) {
					maxRs.add(getHMax(tempList));
					tempList.clear();
				}
			}
		}
		return maxRs;
	}

	/**获取固定区间中K线收盘价的最小值
	 * @param  list K线
	 * @param  interval 区间大小
	 * @return K线列表
	 */
	public static List<KLine> getCPriceMin(List<KLine> list, int interval) {
		List<KLine> tempList = new ArrayList<KLine>();
		List<KLine> maxRs = new ArrayList<KLine>();
		int count = 0;
		for (KLine kLine : list) {
			count++;
			tempList.add(kLine);
			if (count % interval == 0) {
				maxRs.add(getCMin(tempList));
				tempList.clear();
			}
			if (count == list.size()) {
				if (!(list.size() % interval == 0)) {
					maxRs.add(getCMin(tempList));
					tempList.clear();
				}
			}
		}
		return maxRs;
	}

	/**获取固定区间中K线当日最低价的最小值
	 * @param  list K线
	 * @param  interval 区间大小
	 * @return K线列表
	 */
	public static List<KLine> getLPriceMin(List<KLine> list, int interval) {
		List<KLine> tempList = new ArrayList<KLine>();
		List<KLine> maxRs = new ArrayList<KLine>();
		int count = 0;
		for (KLine kLine : list) {
			count++;
			tempList.add(kLine);
			if (count % interval == 0) {
				maxRs.add(getLMin(tempList));
				tempList.clear();
			}
			if (count == list.size()) {
				if (!(list.size() % interval == 0)) {
					maxRs.add(getLMin(tempList));
					tempList.clear();
				}
			}
		}
		return maxRs;
	}
	
	/**获取K线收盘价最大值
	 * @param  K线list
	 * @param
	 * @param
	 * @author  陈集彬
	 * @return  KLine
	 * @date    2016年6月11日
	 */
	public static KLine getCMax(List<KLine> list) {
		KLine temp = list.get(0);
		for (KLine kline : list) {
			if (temp.getClose() < kline.getClose()) {
				temp = kline;
			}
		}
		return temp;
	}
	/**获取K线最高价的最大值
	 * @param   K线list
	 * @param
	 * @param
	 * @author  陈集彬
	 * @return  KLine
	 * @date    2016年6月11日
	 */
	public static KLine getHMax(List<KLine> list) {
		KLine temp = list.get(0);
		for (KLine kline : list) {
			if (temp.getHigh() < kline.getHigh()) {
				temp = kline;
			}
		}
		return temp;
	}
	/**获取K线收盘价最小值
	 * @param   K线list
	 * @param
	 * @param
	 * @author  陈集彬
	 * @return  KLine
	 * @date    2016年6月11日
	 */
	public static KLine getCMin(List<KLine> list) {
		KLine temp = list.get(0);
		for (KLine kline : list) {
			if (temp.getClose() > kline.getClose()) {
				temp = kline;
			}
		}
		return temp;
	}
	/**获取K线最低价的最小值
	 * @param   K线list
	 * @param
	 * @param
	 * @author  陈集彬
	 * @return  KLine
	 * @date    2016年6月11日
	 */
	public static KLine getLMin(List<KLine> list) {
		KLine temp = list.get(0);
		for (KLine kline : list) {
			if (temp.getLow() > kline.getLow()) {
				temp = kline;
			}
		}
		return temp;
	}

    public static double[] standardize(double[] raw) {
        double[] result = new double[raw.length];
        double min = getMin(raw);
        double max = getMax(raw);

        double[] mapped = map(raw, min, max);
        double avg = CalculationUtil.getAverage(mapped);

        double Ssqu = 0;
        for (int i = 0; i < mapped.length; i++) {
            Ssqu += Math.pow(mapped[i] - avg, 2);
        }
        double S = Math.pow(Ssqu / mapped.length, 0.5);

        for (int i = 0; i < mapped.length; i++) {
            result[i] = (mapped[i] - avg) / S;
        }

        return result;
    }
    
    public static double[] standardize(List<Double> raw) {
        double[] result = new double[raw.size()];
        double min = getMin(raw);
        double max = getMax(raw);

        double[] mapped = map(raw, min, max);
        double avg = CalculationUtil.getAverage(mapped);

        double Ssqu = 0;
        for (int i = 0; i < mapped.length; i++) {
            Ssqu += Math.pow(mapped[i] - avg, 2);
        }
        double S = Math.pow(Ssqu / mapped.length, 0.5);

        for (int i = 0; i < mapped.length; i++) {
            result[i] = (mapped[i] - avg) / S;
        }

        return result;
    }
    
    public static List<Double> toDouble(List<KLine> klines) {
        return klines.stream().map(each -> {
            return each.getClose();
        }).collect(Collectors.toList());
    }


    public static double[] map(double[] raw, double min, double max) {
        double[] result = new double[raw.length];
        for (int i = 0; i < raw.length; i++) {
            result[i] = (raw[i] - min) / (max - min);
        }
        return result;
    }
    
    public static double[] map(List<Double> raw, double min, double max) {
        double[] result = new double[raw.size()];
        for (int i = 0; i < raw.size(); i++) {
            result[i] = (raw.get(i) - min) / (max - min);
        }
        return result;
    }

	/**根据价格数组获取最小值
	 * @param   price[]
	 * @param
	 * @param
	 * @author  陈集彬
	 * @return  double
	 * @date    2016年6月11日
	 */
	public static double getMin(double[] price){
		double temp=price[0];
		for(int i=1;i<price.length-1;i++){
			if(price[i]!=0) {
	            if(price[i]<temp) {
	                temp=price[i];
	            }
	        }
		}
		return temp;
	}
	
	public static double getMin(List<Double> data){
		
		double temp=data.get(0);
		for(int i=1;i<data.size()-1;i++){
			double current = data.get(i);
			if(current!=0) {
	            if(current<temp) {
	                temp=current;
	            }
	        }
		}
		return temp;
	}

	/**根据价格数组获取最大值
	 * @param   price[]
	 * @param
	 * @param
	 * @author  陈集彬
	 * @return  double
	 * @date    2016年6月11日
	 */
	public static double getMax(double[] price){
		double temp=price[0];
		for(int i=1;i<price.length-1;i++){
			if(price[i]>temp) {
	            temp=price[i];
	        }
		}
		return temp;
	}
	
	public static double getMax(List<Double> data){
		double temp=data.get(0);
		for(int i=1;i<data.size()-1;i++){
			double current = data.get(i);
			if(current>temp) {
	            temp=current;
	        }
		}
		return temp;
	}

	/**四舍五入保留2位小数
	 * @param
	 * @param
	 * @param
	 * @author  陈集彬
	 * @return  double
	 * @date    2016年6月11日
	 */
	public static double toTwoDecimals(double num){
	
		double temp1=num*1000;
		int temp2=(int) temp1;//3位小数
		if(temp2%10>=5) {
	        temp2+=10;
	    }
		int temp3=temp2/10;   //2位小数
		return (double)temp3/100;
	}

	/**四舍五入保留3位小数
	 * @param
	 * @param
	 * @param
	 * @author  陈集彬
	 * @return  double
	 * @date    2016年6月11日
	 */
	public static double toThreeDecimals(double num){
	
	    double temp1=num*10000;
	    int temp2=(int) temp1;//4位小数
	    if(temp2%10>=5) {
	        temp2+=10;
	    }
	    int temp3=temp2/10;   //3位小数
	    return (double)temp3/1000;
	}

	/**保留特定位小数
	 * @param num
	 * @param decNum 保留小数位
	 * @return
	 */
	public static double toSpecifiedDecimals(double num,int decNum){
	    double temp1 = num* Math.pow(10, decNum+1);
	    int temp2 = (int)temp1;
	    if(temp2%10 >= 5){
	        temp2 += 10;
	    }
	    int temp3 = temp2/10;//decNum小数
	    return temp3/Math.pow(10, decNum);
	
	}

	/**根据传来的参数len计算均值
		 * @param   price[]
		 * @param   type
		 * @param
		 * @author  陈集彬
		 * @return  double
		 * @date    2016年6月11日
		 */
		public static double getAverage(double price[], int len) {
			double count = 0;
			for (int i = 0; i < len; i++) {
				count = count + price[i];
			}
			double rs = count / len;
	//		return rs;
			return toThreeDecimals(rs);
		}

	/**计算价格均值，根据数组长度计算
	 * @param   price[]
	 * @param
	 * @param
	 * @author  陈集彬
	 * @return  double
	 * @date    2016年6月11日
	 */
	public static double getAverage(double price[]) {
		double count = 0;
		for (int i = 0; i < price.length; i++) {
			count = count + price[i];
		}
		double rs = count / price.length;
		return toSpecifiedDecimals(rs, 4);
	}

    /**
     * 计算价格均值，根据数组长度计算
     * 
     * @param price[]
     * @param
     * @param
     * @author 陈集彬
     * @return double
     * @date 2016年6月11日
     */
    public static double calAverages(List<Double> price) {
        double count = 0;
        for (int i = 0; i < price.size(); i++) {
            count = count + price.get(i);
        }
        double rs = count / price.size();
        return toSpecifiedDecimals(rs, 4);
    }

	/**根据K线计算均值
	 * @param
	 * @param
	 * @param
	 * @author  陈集彬
	 * @return  double
	 * @date    2016年6月11日
	 */
	public static double getAverage(List<KLine> list) {
		double count = 0;
		for(KLine kline:list){
			count+=kline.getClose();
		}
		double rs = count/ list.size();
		return toTwoDecimals(rs);
	}

	/**根据传来的参数求均值
	 * @param
	 * @param
	 * @param
	 * @author  陈集彬
	 * @return  double
	 * @date    2016年6月11日
	 */
	public static double getAverageByN(double price[],int N) {
		double count = 0;
		for (int i = 0; i < N; i++) {
			count = count + price[i];
		}
		double rs = count/ N;
		return toTwoDecimals(rs);
	}

	/**通过移动窗口的方法来实现数据更新
	 * @param    price[]
	 * @param   newPrice
	 * @param
	 * @author  陈集彬
	 * @return  double[]
	 * @date    2016年6月11日
	 */
	public static double[] moveWindow(double price[], double newPrice) {
	
		for (int i = 0; i < price.length - 1; i++) {
			price[i] = price[i + 1];
		}
		price[price.length - 1] = newPrice;
		return price;
	}

	/**通过更新Mark对应的值来更新数据
	 * @param
	 * @param
	 * @param
	 * @author  陈集彬
	 * @return  double[]
	 * @date    2016年6月11日
	 */
	public static double[] updateMark(double[] price, double newPrice) {
	
		// 取出mark的值
		int marks = (int) price[price.length - 1];
		if (marks >= 0 && marks <= (price.length - 2)) {
			// 更改mark对应的数组
			price[marks] = newPrice;
			++marks;
			if (marks == price.length - 1) {
				marks = 0;
				price[price.length - 1] = marks;
			}
			price[price.length - 1] = marks;
			return price;
		}
		return new double[]{-1};
	}

	/**计算比率
	 * @param preMa
	 * @param thisMa
	 * @param decNum
	 * @return
	 */
	public static Double getRange(Double preMa,Double thisMa,int decNum){
	    if(preMa==null||thisMa==null||preMa==0||thisMa==0){
	        throw new NullPointerException();
	    }
	    return toSpecifiedDecimals((thisMa-preMa)/preMa, decNum);
	}

	public static Double getRangeIgnoreZero(Double preMa,Double thisMa,int decNum){
	    if(preMa==null||thisMa==null||preMa==0||thisMa==0){
	    	return -1111.0;
	    }
	    return toSpecifiedDecimals((thisMa-preMa)/(preMa<0 ? -preMa:preMa), decNum);
	}
}
